1. Introduction
2. Example 1
3. Example 2 - Sleep and Interrupt

1. Introduction

We can influence

Invoking sleep does not release ownership of locks. It should be called outside synchronized blocks and methods to avoid deadlock .

When using multiple threads we want to achieve one of these goals:

An example of the first concern would be a multi-user web application, we don't want a single user to be served while the rest is waiting before a blank screen.

An example of the second concern would be a desktop application generating different calculation intensive reports in the background. We don't want the user interface to freeze during five minutes while the report is generated.

Thread States - State Diagram
Thread States - State Diagram

2. Example 1

2.1. Base Code

package be.ooxs.examples.threads;

public class ThreadDemoSleepEtc {

	public static void main(String[] args) throws InterruptedException {
		StringBuilder b = new StringBuilder();
		Thread[] threads = new Thread[] {
				new Thread(new Producer("A", b)), 
				new Thread(new Producer("B", b)), 
				new Thread(new Producer("C", b)), 
				new Thread(new Producer("D", b)),
				new Thread(new Producer("E", b)), 
				new Thread(new Producer("F", b)), 
				new Thread(new Producer("G", b)) };
		for (Thread thread : threads) {
			thread.start();
		}
		for (Thread thread : threads) {
			thread.join();
		}
		System.out.println(b);
		System.out.println("Done");
	}
}

class Producer implements Runnable {
	private String name;
	private StringBuilder buffer;

	public Producer(String name, StringBuilder buffer) {
		super();
		this.name = name;
		this.buffer = buffer;
	}

	public void run() {
		for (int i = 0; i < 50; i++) {
			print(i);
		}
	}

	private void print(int i) {
		buffer.append(name);
		buffer.append(": ");
		buffer.append(i);
		buffer.append('\n');
	}
}

Now, when we look at the output of our 7 thread program, we see that each task finishes before the other. We might as well not have used threads.

The fact is that the computer I run this on hardly notices the little program and the scheduler hasn't time to intervene. If we're trying to get the job done as fast as possible, this is probably just fine. (second concern in the list above)

When the processor workload increases due to external factors or because our program has to do more, the image will change and the output will get mixed. It is multi threaded after all.

A: 0
...
A: 49
B: 0
...
B: 49
C: 0
...
C: 49
D: 0
...
D: 49
E: 0
...
E: 49
F: 0
...
F: 49
G: 0
...
G: 49

Done

2.2. Using Sleep

If, however, we are polling for the state of some resource. Or generally concerning ourselves with distributing processing time equally (first concern in list above), we need to do something.

Let's modify the print method a little. We make the current thread go to sleep for a while:

...
	private void print(int i) {
		try {
			Thread.sleep(100);
			buffer.append("waking up - ");
		} catch (InterruptedException exception) {
			Logger.getLogger(Producer.class.getName()).log(Level.INFO, "print threw InterruptedException", exception);
		}
		buffer.append(name);
		buffer.append(": ");
		buffer.append(i);
		buffer.append('\n');
	}
...

The result is completely different, the threads get some execution time in turn. Mostly the sequence repeats itself (B,C,A,F,G,D,E) when running the program, but that's a coincidence. It does change from time to time.

...
waking up - E: 26
waking up - F: 26
waking up - C: 27
waking up - A: 27
waking up - B: 27
waking up - G: 27
...
waking up - G: 48
waking up - D: 48
waking up - E: 48
waking up - B: 49
waking up - C: 49
waking up - A: 49
waking up - F: 49
waking up - G: 49
waking up - D: 49
waking up - E: 49

Done

2.3. Using Yield

An alternative is to use yield , it hints at the scheduler that the current thread doesn't desperately need more processing time.

...
	private void print(int i) {
		Thread.yield();
		buffer.append(name);
		buffer.append(": ");
		buffer.append(i);
		buffer.append('\n');
	}
...

However, since this small program doesn't test the processor and JVM to its limits, there is very little impact to show. The threads get each in turn a small slice of time to print out some numbers.

A: 0
A: 1
...
A: 49
B: 0
...

3. Example 2 - Sleep and Interrupt

In this example we have 3 threads. The main thread starts two other threads ta and tb . Both threads print something and then go to sleep. The main thread then interrupts thread ta , "A2" is not printed, "A Exception" is printed instead - the communication is done via the Exception.

package be.ooxs.examples.threads;

public class TreadSleepSingle {
	public static void main(String[] args) {
		System.out.println("M 1");
		Thread ta = new Thread(new RunnableA());
		Thread tb = new Thread(new RunnableB());
		System.out.println("M 2");
		ta.start();
		System.out.println("M 3");
		tb.start();
		System.out.println("M 4");
		ta.interrupt();
		System.out.println("M 5");
	}

}

class RunnableA implements Runnable {

	@Override
	public void run() {
		System.out.println("A 1");
		try {
			Thread.sleep(1000);
			System.out.println("A 2");
		} catch (InterruptedException exception) {
			System.out.println("A Exception");
		}
		System.out.println("A 3");
	}

}

class RunnableB implements Runnable {

	@Override
	public void run() {
		System.out.println("B 1");
		try {
			Thread.sleep(500);
			System.out.println("B 2");
		} catch (InterruptedException exception) {
			System.out.println("B Exception");
		}
		System.out.println("B 3");
	}
}
M 1
M 2
A 1
M 3
B 1
M 4
A Exception
A 3
M 5
B 2
B 3